/**************************************************************************
 *
 * Copyright (c) 2015-2017  QIKU Company             　　　　　　　            
 *                 奇酷软件（深圳）有限公司  版权所有 2015-2017
 *
 * PROPRIETARY RIGHTS of QIKU Company are involved in the  　　　　　　     
 * subject matter of this material.  All manufacturing, reproduction, use, 
 * and sales rights pertaining to this subject matter are governed by the  
 * license agreement.  The recipient of this software implicitly accepts   
 * the terms of the license.                                               
 * 本软件文档资料是奇酷公司的资产,任何人士阅读和使用本资料必须获得                     
 * 相应的书面授权,承担保密责任和接受相应的法律约束.                                 
 *
 **************************************************************************/
package com.yw.android.common.utils;

import android.annotation.SuppressLint;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
 * AES加密工具
 *
 * @author yuanwei
 */
public class AESEncoder {
    /**
     * AES加密模式
     */
    private final static String MODE = "AES/CFB/NoPadding";

    /**
     * 向量定义
     */
    private final static byte[] IV = new byte[]{
            '0', '1', '0', '2', '0', '3', '0', '4',
            '0', '5', '0', '6', '0', '7', '0', '8'};

    /**
     * 使用AES加密，内部对KEY进行MD5编码
     *
     * @param plain 需要加密的内容
     * @param key   加密密码
     * @return 加密后字符串
     * @throws Exception 异常定义
     */
    public static String encrypt(String plain, String key)
            throws Exception {
        return byte2Hex(encrypt(plain.getBytes("UTF-8"), key));
    }

    /**
     * 使用AES加密，内部对KEY进行MD5编码
     *
     * @param plain 需要加密的内容
     * @param key   加密密码
     * @return 加密后字符串
     * @throws Exception 异常定义
     */
    @SuppressLint("TrulyRandom")
    public static byte[] encrypt(byte[] plain, String key)
            throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] kb = md.digest(key.getBytes("UTF-8"));

            IvParameterSpec iv = new IvParameterSpec(IV);
            SecretKeySpec spec = new SecretKeySpec(kb, "AES");

            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(MODE);
            cipher.init(Cipher.ENCRYPT_MODE, spec, iv);

            // 加密
            return cipher.doFinal(plain);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(NoSuchAlgorithmException)", e);
        } catch (NoSuchPaddingException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(NoSuchPaddingException)", e);
        } catch (InvalidKeyException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(InvalidKeyException)", e);
        } catch (IllegalBlockSizeException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(IllegalBlockSizeException)", e);
        } catch (BadPaddingException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(BadPaddingException)", e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(UnsupportedEncodingException)", e);
        } catch (NumberFormatException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(NumberFormatException)", e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new Exception("[" + key
                    + "] encrypt failed(InvalidAlgorithmParameterException)", e);
        }
    }

    /**
     * 对AES加密字符串解密
     *
     * @param cipherText 使用AES加密的字符串
     * @param key        加密密码
     * @return 解密后明文
     * @throws Exception 异常定义
     */
    public static String decrypt(String cipherText, String key)
            throws Exception {
        return new String(decrypt(hex2Byte(cipherText), key));
    }

    /**
     * 对AES加密字符串解密
     *
     * @param cipherText 使用AES加密的字符串
     * @param key        加密密码
     * @return 解密后明文
     * @throws Exception 异常定义
     */
    public static byte[] decrypt(byte[] cipherText, String key)
            throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] kb = md.digest(key.getBytes("UTF-8"));

            IvParameterSpec iv = new IvParameterSpec(IV);
            SecretKeySpec spec = new SecretKeySpec(kb, "AES");

            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(MODE);
            cipher.init(Cipher.DECRYPT_MODE, spec, iv);

            // 解密
            return cipher.doFinal(cipherText);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(NoSuchAlgorithmException)", e);
        } catch (NoSuchPaddingException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(NoSuchPaddingException)", e);
        } catch (InvalidKeyException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(InvalidKeyException)", e);
        } catch (IllegalBlockSizeException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(IllegalBlockSizeException)", e);
        } catch (BadPaddingException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(BadPaddingException)", e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(UnsupportedEncodingException)", e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new Exception("[" + key
                    + "] decrypt failed(InvalidAlgorithmParameterException)", e);
        }
    }

    /**
     * 将数组转换成十六进制字符串
     *
     * @param b 数组
     * @return 转化后的十六进制字符串
     */
    private static String byte2Hex(byte[] b) {
        StringBuffer hexs = new StringBuffer();

        for (int i = 0; i < b.length; i++) {
            hexs.append(Integer.toHexString((b[i] >>> 4) & 0xF));
            hexs.append(Integer.toHexString(b[i] & 0xF));
        }

        return hexs.toString().toLowerCase(Locale.getDefault());
    }

    /**
     * 将十六进制字符串转换成数组
     *
     * @param hexs 十六进制字符串
     * @return 转化后的数组
     */
    private static byte[] hex2Byte(String hexs) {
        char[] c = hexs.toLowerCase(Locale.getDefault()).toCharArray();
        int len = (c.length / 2);
        byte[] b = new byte[len];

        for (int i = 0; i < len; i++) {
            int pos = (i * 2);
            b[i] = (byte) (hex2Int(c[pos]) << 4 | hex2Int(c[pos + 1]));
        }

        return b;
    }

    /**
     * 将十六进制字符转换为整型数字
     *
     * @param c 十六进制字符
     * @return 整型数字
     */
    private static int hex2Int(char c) {
        if (('0' <= c) && (c <= '9')) {
            return (c - '0');
        } else if (('A' <= c) && (c <= 'F')) {
            return (c - 'A' + 10);
        } else if (('a' <= c) && (c <= 'f')) {
            return (c - 'a' + 10);
        } else {
            return 0;
        }
    }
}
